package com.hbqyml.common.config;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 加入模糊匹配 验证功能
 *
 * @version 4.0.0
 */
public class ParseDate {
    public static void main(String[] args) {

        Date parse = parse("2026-12-31jvhjjhigfyfyuuhvfg 12:12:21");
        String newdate = newdate(parse);
        String newdateday = newdateday(parse);
        System.out.println(newdate);
        System.out.println(newdateday);
    }

    // HH 24 hh 12
    public final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public final static SimpleDateFormat Psdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

    public static SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");

    public static SimpleDateFormat date1 = new SimpleDateFormat("yyyy-MM");

    public static SimpleDateFormat week = new SimpleDateFormat("EEEE");

    public static TimeZone timeZone = TimeZone.getTimeZone("GMT+8");

    static {
        sdf.setTimeZone(timeZone);
        date.setTimeZone(timeZone);
        date1.setTimeZone(timeZone);
        week.setTimeZone(timeZone);
    }

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static String newdate() {
        return sdf.format(currentDate());
    }

    public static String Pdate(Date date) {
        return Psdf.format(date);
    }

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static String newdate(Date date) {
        return sdf.format(date);
    }

    /**
     * yyyy-MM-dd
     */
    public static String newdateday() {
        return date.format(currentDate());
    }

    /**
     * yyyy-MM-dd
     */
    public static String newdateday(Date date1) {
        return date.format(date1);
    }

    public static String newdatemon(Date date) {
        return date1.format(date);
    }

    public String toString() {
        Date d = currentDate();
        return String.format("%tF %tT.%tL", d, d, d);
    }

    /**
     * EEEE
     */
    public static String week(Date date) {
        return week.format(date);
    }

    /**
     * EEEE
     */
    public static int getWeekint(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK) - 1;
    }

    public static Date currentDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(timeZone);
        return calendar.getTime();
    }

    private final static String patternDate = "\\d{4}(\\-|\\/|.){1}\\d{2}\\1\\d{2}";
    private final static String patternDateStr = "[\\x21-\\x7e| |\u4e00-\u9fa5]*\\d{4}[.|\\-|\\/]\\d{2}[.|\\-|\\/]\\d{2}[\\x21-\\x7e| |\u4e00-\u9fa5]*";
    private final static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.BASIC_ISO_DATE;
    private final static DateTimeFormatter dateTimeFormatterTime = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm:ss");
    private final static DateTimeFormatter dateTimeFormatterTimeS = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final static ZoneId zoneId = ZoneId.of("Asia/Shanghai");
    private final static String patternDateTime = "\\d{4}(\\-|\\/|.)\\d{2}\\1\\d{2} ([0-9]{2})(:|\\1)([0-9]{2})(:|\\1)([0-9]{2})";
    private final static String patternDateTimeStr = "[\\x21-\\x7e| |\u4e00-\u9fa5]*\\d{4}(\\-|\\/|.)\\d{1,2}\\1\\d{1,2} ([0-9]{2})(:|\\1)([0-9]{2})(:|\\1)([0-9]{2})[\\x21-\\x7e| |\u4e00-\u9fa5]*";
    private final static String patternDateTimeNumber = "\\d+";
    private final static String patternDateTimeS = "\\d{4}(\\-|\\/)\\d{2}\\1\\d{2} ([0-9]{2})(:|\\1)([0-9]{2})(:|\\1)([0-9]{2}).[0-9]{1,3}";
    private final static String patternDateTimeM = "\\d{4}(\\-|\\/|.)\\d{2}\\1\\d{2} ([0-9]{2})(:)([0-9]{2})";
    private final static String PpatternDateTimeM = "[\\x21-\\x7e| |\u4e00-\u9fa5]*\\d{4}(\\-|\\/|.)\\d{2}\\1\\d{2} ([0-9]{2})(:)([0-9]{2})[\\x21-\\x7e| |\u4e00-\u9fa5]*";
    ;
    private final static Pattern patT = Pattern.compile("\\d{4}[.|\\-|\\/]\\d{2}[.|\\-|\\/]\\d{2}");
    private final static Pattern patTS = Pattern.compile(patternDateTime);
    private final static Pattern patTM = Pattern.compile(patternDateTimeM);
    private final static int utcPcst = 8 * 3600;
    private final static ZoneOffset CST_Zone = ZoneOffset.ofTotalSeconds(utcPcst);

    /**
     * @param date 1614136752000 = true time:0
     * @param date 2020.01.02 = true time:10
     * @param date 2020/01/02 = true time:10
     * @param date 2020-01-02 = true time:10
     * @param date 2020-01-02 00:00:00 = true time:10
     * @param date 2020-01-02 00:00 true time:12
     * @param date 2020.01.02 00:00:00 = true time:15
     * @param date 2020/01/02 00:00:00 = true time:7
     * @param date 2020/01/02 00:00:00.0 = true time:16
     * @param date 2020/01/02 00:00:00.12 = true time:13
     * @param date 2020/01/02 00:00:00.123 = true time:11
     * @param date 2020-01-02 00:00:00.123 = true time:11
     * @param date sdhasb 2020-01-02 00:00:00 asdashdbaj = true time:14
     * @param date sdhasb 2020-01-02 asdashdbaj = true time:15
     */
    public static Date parse(String date) {
        try {
            if (date == null) {
                return null;
            }
            if (date.matches(patternDateTimeNumber)) {
                return new Date(Long.parseLong(date));
            } else if (date.matches(patternDateTime)) {
                return Date.from(LocalDateTime.parse(date.replaceAll("[\\/|.]", "-"), dateTimeFormatterTime)
                        .toInstant(CST_Zone));
            } else if (date.matches(patternDate)) {
                return parseNumber(date.replaceAll("[\\-|\\/|.]", ""));
            } else if (date.matches(patternDateTimeS)) {
                String newTime = date.replaceAll("[\\/]", "-");
                if (newTime.length() == 21) {
                    newTime += "00";
                } else if (newTime.length() == 22) {
                    newTime += "0";
                }
                return Date.from(LocalDateTime.parse(newTime, dateTimeFormatterTimeS).toInstant(CST_Zone));
            } else if (date.matches(patternDateTimeStr)) {
                Matcher matcher = patTS.matcher(date);
                while (matcher.find()) {
                    date = matcher.group().replaceAll("[\\/|.]", "-");
                    String[] zu = date.split(" ");
                    String[] qP = zu[0].split("-");
                    String[] hP = zu[1].split(":");
                    int y = Integer.parseInt(qP[0]);
                    int M = Integer.parseInt(qP[1]);
                    int d = Integer.parseInt(qP[2]);
                    int h = Integer.parseInt(hP[0]);
                    int m = Integer.parseInt(hP[1]);
                    int s = Integer.parseInt(hP[2]);
                    boolean bit = M < 13 && M > 0
                            ? !((M == 1 || M == 3 || M == 5 || M == 7 || M == 8 || M == 10 || M == 12)
                            ? d < 1 || d > 32
                            : (M == 4 || M == 6 || M == 9 || M == 11) ? d < 1 || d > 31
                            : M == 2 ? (y % 4 == 0 && y % 100 != 0) || y % 400 == 0
                            : d < 1 || d > 28)
                            : false;
                    boolean nian = bit ? !(h < 0 || h > 23 || m < 0 || m > 59 || s < 0 || s > 59) : true;
                    if (nian) {
                        return Date.from(LocalDateTime.parse(date, dateTimeFormatterTime).toInstant(CST_Zone));
                    } else if (bit) {
                        return parseNumber(new StringBuilder(y).append(M).append(d).toString());
                    }
                }
            } else if (date.matches(patternDateTimeM)) {
                return Date
                        .from(LocalDateTime.parse(date.replaceAll("[\\/|.]", "-") + ":00", dateTimeFormatterTime)
                                .toInstant(CST_Zone));
            } else if (date.matches(PpatternDateTimeM)) {
                Matcher matcher = patTM.matcher(date);
                while (matcher.find()) {
                    date = matcher.group().replaceAll("[\\/|.]", "-") + ":00";
                    String[] zu = date.split(" ");
                    String[] qP = zu[0].split("-");
                    String[] hP = zu[1].split(":");
                    int y = Integer.parseInt(qP[0]);
                    int M = Integer.parseInt(qP[1]);
                    int d = Integer.parseInt(qP[2]);
                    int h = Integer.parseInt(hP[0]);
                    int m = Integer.parseInt(hP[1]);
                    boolean bit = M < 13 && M > 0
                            ? !((M == 1 || M == 3 || M == 5 || M == 7 || M == 8 || M == 10 || M == 12)
                            ? d < 1 || d > 32
                            : (M == 4 || M == 6 || M == 9 || M == 11) ? d < 1 || d > 31
                            : M == 2 ? (y % 4 == 0 && y % 100 != 0) || y % 400 == 0
                            : d < 1 || d > 28)
                            : false;
                    boolean nian = bit ? !(h < 0 || h > 23 || m < 0 || m > 59) : true;
                    if (nian) {
                        return Date.from(LocalDateTime.parse(date, dateTimeFormatterTime).toInstant(CST_Zone));
                    } else if (bit) {
                        return parseNumber(new StringBuilder(y).append(M).append(d).toString());
                    }
                }
            } else if (date.matches(patternDateStr)) {
                Matcher matcher = patT.matcher(date);
                while (matcher.find()) {
                    date = matcher.group();
                    String[] qP = date.split("[\\-|\\/|.]");
                    int y = Integer.parseInt(qP[0]);
                    int M = Integer.parseInt(qP[1]);
                    int d = Integer.parseInt(qP[2]);
                    boolean bit = M < 13 && M > 0
                            ? !((M == 1 || M == 3 || M == 5 || M == 7 || M == 8 || M == 10 || M == 12)
                            ? d < 1 || d > 32
                            : (M == 4 || M == 6 || M == 9 || M == 11) ? d < 1 || d > 31
                            : M == 2 ? (y % 4 == 0 && y % 100 != 0) || y % 400 == 0
                            : d < 1 || d > 28)
                            : false;
                    if (bit) {
                        return parseNumber(matcher.group().replaceAll("[\\-|\\/|.]", ""));
                    }
                }
            }
            return null;
        } catch (DateTimeParseException e) {
            throw new DateTimeParseException(e.getMessage(), date, 0);
        }
    }

    /**
     * <pre>
     * yyyy year 年
     * MM month 月
     * dd day 天
     * HH hour 小时
     * mm minute 分
     * ss second 秒 SSS
     * millisecond 毫秒 ....
     * </pre>
     */
    public final static Date parse(String date, String format) {
        return Date.from(LocalDateTime.parse(date, DateTimeFormatter.ofPattern(format)).toInstant(CST_Zone));
    }

    /**
     * 2020-02-01 12:30:00
     */
    public final static String format() {
        return format(currentDate());
    }

    /**
     * 2020-02-01 12:30:00.123
     */
    public final static String formatS() {
        return formatS(currentDate());
    }

    /**
     * 2020-02-01 12:30:00
     */
    public final static String format(Date date) {
        return String.format("%tF %tT.%tL", date, date, date);
    }

    /**
     * 2020-02-01 12:30:00.123
     */
    public final static String formatS(Date date) {
        return String.format("%tF %tT.%tL", date, date, date);
    }

    /**
     * <pre>
     * yyyy year 年
     * MM month 月
     * dd day 天
     * HH hour 小时
     * mm minute 分
     * ss second 秒 SSS
     * millisecond 毫秒 ....
     * </pre>
     */
    public final static String formatS(Date date, String format) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * @param date 20200102 = true
     */
    public static Date parseNumber(String date) {
        return Date.from(LocalDate.parse(date, dateTimeFormatter).atStartOfDay(zoneId).toInstant());
    }

    /**
     * 计算时间
     */
    public static Date addDay(Date date, Integer day, int i) {
        if (date == null) {
            return null;
        }
        if (day == null) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(i, day);
        return calendar.getTime();
    }

    /**
     * 计算时间
     */
    public static Date addDay(Date date, Integer day) {
        return addDay(date, day, Calendar.DAY_OF_YEAR);
    }

    /**
     * 鑾峰彇姣忎釜鏈堢殑姣忎竴澶� year 鍝竴骞� month 鍝釜鏈� bool 鏄惁瓒呰繃褰撳墠鏃ユ湡
     */
    public static List<Date> getDatesByYearAndMonth(int year, int month, boolean bool) {
        long time = new Date().getTime();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(timeZone);
        calendar.set(year, month - 1, 1);
        List<Date> list = new ArrayList<Date>();
        do {
            list.add(calendar.getTime());
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            if ((!bool) && calendar.getTime().getTime() > time) {
                break;
            }
        } while (month - 1 == calendar.get(Calendar.MONTH));
        return list;
    }

    /**
     * 鑾峰彇姣忎釜鏈堢殑姣忎竴澶�
     */
    public static List<Date> getDatesByYearAndMonth(String year, String month) {
        if (year == null || "".equals(year)) {
            year = newdateday().split("-")[0];
        }
        return getDatesByYearAndMonth(Integer.parseInt(year), Integer.parseInt(month), false);
    }

    /**
     * 鑾峰彇姣忎釜鏈堢殑姣忎竴澶�
     */
    public static List<Date> getDatesByYearAndMonth(String month) {
        if (month == null || "".equals(month)) {
            month = newdateday().split("-")[1];
        }
        return getDatesByYearAndMonth(null, month);
    }

    /**
     * 鑾峰彇姣忎釜鏈堢殑姣忎竴澶�
     */
    public static List<Date> getDatesByYearAndMonth() {
        return getDatesByYearAndMonth(null);
    }
}
